#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>

#define SEP " "
#define NUM 1024
#define SIZE 128

#define DROP_SPACE(s) do { while(isspace(*s)) s++; } while(0)

char command_line[NUM];
char *command_args[SIZE];

char env_buffer[NUM];

#define NONE_REDIR -1
#define INPUT_REDIR 0
#define OUTPUT_REDIR 1
#define APPEND_REDIR 2

extern char **environ;

int g_redir_flag = NONE_REDIR;
char* g_redir_filename = NULL;

int ChangDir(const char* new_path)
{
    chdir(new_path);

    return 0;
}

void PutEnvInMyShell(char* new_env)
{
    putenv(new_env);
}

void CheckDir(char* commands)
{
    assert(commands);

    char* start = commands;
    char* end = commands + strlen(commands);

    while(start < end)
    {
        if(*start == '>')
        {
            if(*(start + 1) == '>')
            {
                *start = '\0';
                start += 2;
                g_redir_flag = APPEND_REDIR;
                DROP_SPACE(start);
                g_redir_filename = start;
                break;
            }
            else
            {
                *start = '\0';
                ++start;
                DROP_SPACE(start);
                g_redir_flag = OUTPUT_REDIR;
                g_redir_filename = start;
                break;
            }
        }
        else if(*start == '<')
        {
            *start = '\0';
            ++start;
            DROP_SPACE(start);
            g_redir_flag = INPUT_REDIR;
            g_redir_filename = start;
            break;
        }
        else
        {
            ++start;
        }
    }
}

int main()
{
    while(1)
    {
        g_redir_flag = NONE_REDIR;
        g_redir_filename = NULL;

        // 1. 显示提示符
        printf("[李四@我的主机名 当前目录]# ");
        fflush(stdout);

        // 2. 获取用户输入
        memset(command_line, '\0', sizeof(command_line) * sizeof(char));
        fgets(command_line, NUM, stdin);
        command_line[strlen(command_line) - 1] = '\0';

        // 检查是否有重定向
        CheckDir(command_line);

        // 3. 字符串切分
        command_args[0] = strtok(command_line, SEP);
        int index = 1;

        // 给ls命令添加颜色
        if(strcmp(command_args[0], "ls") == 0)
        {
            command_args[index++] = (char*)"--color=auto";
        }

        while(command_args[index++] = strtok(NULL, SEP));

        // 4. 内建命令
        if(strcmp(command_args[0], "cd") == 0 && command_args[1] != NULL)
        {
            ChangDir(command_args[1]);
            continue;
        }
        if(strcmp(command_args[0], "export") == 0 && command_args[1] != NULL)
        {
            strcpy(env_buffer, command_args[1]);
            PutEnvInMyShell(env_buffer);
            continue;
        }

        // 5. 创建进程, 执行
        pid_t id = fork();
        if(id == 0)
        {
            int fd = -1;
            switch(g_redir_flag)
            {
            case NONE_REDIR:
                break;
            case INPUT_REDIR:
                fd = open(g_redir_filename, O_RDONLY);
                dup2(fd, 0);
                break;
            case OUTPUT_REDIR:
                fd = open(g_redir_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
                dup2(fd, 1);
                break;
            case APPEND_REDIR:
                fd = open(g_redir_filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
                dup2(fd, 1);
                break;
            default:
                printf("Bug\n");
                break;
            }

            // 6. 进程替换
            execvp(command_args[0], command_args);
            exit(1); // 执行到这里，说明子进程替换失败
        }

        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0)
        {
            if(WIFEXITED(status))
            {
                printf("等待子进程成功: exit code: %d\n", WEXITSTATUS(status));
            }
        }
    }




    return 0;
}